#include "GameAi.h"
#include "Team.h"
#include "TeamManager.h"
#include "League.h"
#include "Player.h"
#include "PlayerManager.h"
#include "PlayerFunctors.h"
#include "ServiceProvider.h"

#include <algorithm>
#include <cassert>
#include <map>

GameAI::GameAI(ServiceProvider* const i_sp)
	:m_sp(i_sp)
{
	assert(m_sp);
}

void GameAI::AssignPlayersOnTeams(LeagueVec& o_league) const
{
	typedef int														KeyType;
	typedef std::multimap<KeyType, Team*, std::greater<KeyType> >	TeamsScore;
	typedef TeamsScore::iterator									TeamsScoreIterator;
	typedef TeamsScore::reverse_iterator							TeamsScoreRIterator;
	typedef std::pair<KeyType, Team*>								TeamPair;

	// initing teams with scores

	TeamsScore teams;

	for (size_t i = 0; i < o_league.size(); ++i)
	{
		const TeamVec& team = o_league[i]->GetTeams();
		TeamVecCit end = team.end();
		TeamVecCit it = team.begin();
		const int pro_factor = o_league[i]->GetLayerIndex();
		for(it; it != end; ++it)
		{
			KeyType strenght = (pro_factor * -20) + (rand()%50);
			TeamPair insertion(strenght, *it);
			teams.insert(insertion);
		}
	}

	// creating player buffer for teams

	int maxPlayer = Team::GetParams().STARTING_TEAM_PLAYERS * teams.size();
	PlayerVec players;
	players.reserve(maxPlayer);
	
	PlayerManager& playerMgr = m_sp->GetPlayerMgr();
	for(int i = 0; i < maxPlayer; ++i)
		players.push_back(playerMgr.GetNewPlayer());

	std::sort(players.begin(),players.end(), PlayerComparisionAverageSkill);

	// teams choose players according to team score and players skills

	PlayerVecIt playersIt = players.begin();
	PlayerVecIt playersEnd = players.end();
	for(;playersIt != playersEnd && !teams.empty(); ++playersIt)
	{
		TeamsScoreIterator rIt = teams.begin();
		TeamPair candidate = *rIt;
		teams.erase(rIt);

		//(*playersIt)->SetGoalKeeper(false);
		candidate.second->AddPlayer(*playersIt);

		if(candidate.second->GetPlayersList().size() < Team::GetParams().STARTING_TEAM_PLAYERS)
		{
			candidate.first -= (rand()%10);
			teams.insert(candidate);
		}
	}

	// here each team has filled its rooster, but no guarantee that roles are ok
	int minimumPlayersPerRole[NUM_ROLES] = {Team::GetParams().TITOLARS_GOALKEEPERS*2,
		Team::GetParams().TITOLARS_DEFENDERS*2, Team::GetParams().TITOLARS_ATTACKERS*2};

	for (size_t i = 0; i < o_league.size(); ++i)
	{
		TeamVec& team = o_league[i]->GetTeams();
		TeamVecCit end = team.end();
		TeamVecCit it = team.begin();
		for(it; it != end; ++it)
		{
			Team& theTeam = *(*it);

			PlayerVec thePlayerList = theTeam.GetPlayersList();
			std::random_shuffle(thePlayerList.begin(), thePlayerList.end());
			size_t currentRole = 0;

			for(int j = 0; j < NUM_ROLES; ++j)
			{
				for(int k = 0; k < minimumPlayersPerRole[j]; ++k)
				{
					assert(currentRole < thePlayerList.size());
					thePlayerList[currentRole]->SetRole(j);
					++currentRole;
				}
			}
		}
	}
}

void GameAI::PreMatchUpdate(const bool i_doNotPrompt) const
{
	const TeamVec& tl = m_sp->GetTeamMgr().GetTeams();

	// Sells
	for(size_t j = 0; j < tl.size(); ++j)
	{
		Team& team = *tl[j];
		if(!team.IsUserControlled())
			team.GetTeamAI().TrySell(i_doNotPrompt);
	}

	// Buy
	for(size_t j = 0; j < tl.size(); ++j)
	{
		Team& team = *tl[j];
		if(!team.IsUserControlled())
			team.GetTeamAI().TryBuy(i_doNotPrompt);
	}

	// Formation
	for(size_t j = 0; j < tl.size(); ++j)
	{
		Team& team = *tl[j];
		if(!team.IsUserControlled())
			team.GetTeamAI().MakeFormation(i_doNotPrompt);
	}

	if(!i_doNotPrompt)
		std::cout << std::endl;
}
